package com.bifrost.service.impl;

import com.bifrost.constant.OrderReturnStatus;
import com.bifrost.constant.OrderType;
import com.bifrost.constant.RefundStatus;
import com.bifrost.constant.ReturnType;
import com.bifrost.entity.Category;
import com.bifrost.entity.CouponDetail;
import com.bifrost.entity.CouponHistroy;
import com.bifrost.entity.MerchantStore;
import com.bifrost.entity.Order;
import com.bifrost.entity.OrderReturn;
import com.bifrost.entity.OrderReturnItem;
import com.bifrost.entity.ProductBrand;
import com.bifrost.entity.ProductSku;
import com.bifrost.entity.User;
import com.bifrost.exception.OrderReturnAuditException;
import com.bifrost.model.ReturnAuditModel;
import com.bifrost.model.vo.OrderReturnItemVO;
import com.bifrost.model.vo.OrderReturnVO;
import com.bifrost.model.vo.PageVO;
import com.bifrost.repository.CouponDetailRepository;
import com.bifrost.repository.CouponHistroyRepository;
import com.bifrost.repository.CouponRepository;
import com.bifrost.repository.OrderReturnItemRepository;
import com.bifrost.repository.OrderReturnRepository;
import com.bifrost.repository.ProductBrandRepository;
import com.bifrost.repository.ProductSkuRepository;
import com.bifrost.service.AdminOrderReturnService;
import com.bifrost.service.BonusPointsService;
import com.bifrost.service.RefundRequestService;
import com.bifrost.uid.UidGenerator;
import com.bifrost.util.DateUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service("adminOrderReturnService")
public class AdminOrderReturnServiceImpl implements AdminOrderReturnService {

    @Autowired
    private OrderReturnRepository orderReturnRepository;
    @Autowired
    private ProductSkuRepository productSkuRepository;
    @Autowired
    private OrderReturnItemRepository orderReturnItemRepository;
    @Autowired
    private ProductBrandRepository productBrandRepository;
    @Autowired
    CouponDetailRepository couponDetailRepository;
    @Autowired
    RefundRequestService refundRequestService;
    @Autowired
    BonusPointsService bonusPointsService;
    @Autowired
    CouponRepository couponRepository;
    @Autowired
    UidGenerator defaultUidGenerator;
    @Autowired
    CouponHistroyRepository couponHistroyRepository;

    /**
     * 退单项条件分页查询
     *
     * @param merchantStoreIdList
     * @param pageCode
     * @param pageSize
     * @return
     */
    @Override
    public PageVO findByPage(String returnType, String orderReturnNumber, String originalOrderNumber, String orderReturnStatus, List<Long> merchantStoreIdList, String productCode, String productName, String startTime, String endTime, Integer pageCode, Integer pageSize) {
        Pageable pageable = new PageRequest(pageCode - 1, pageSize);
        Specification<OrderReturnItem> specification = new Specification<OrderReturnItem>(){
            @Override
            public Predicate toPredicate(Root<OrderReturnItem> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();
                if(StringUtils.isNotBlank(returnType)){
                    //增加查询条件，退单类型
                    Join<OrderReturnItem, OrderReturn> join = root.join("orderReturn");
                    Path<String> rootReturnType = join.get("returnType");
                    predicates.add(cb.equal(rootReturnType,returnType));
                }
                if(StringUtils.isNotBlank(orderReturnNumber)){
                    //增加查询条件，退单号
                    Join<OrderReturnItem, OrderReturn> join = root.join("orderReturn");
                    Path<String> queryReturnNumber = join.get("returnNumber");
                    predicates.add(cb.like(queryReturnNumber,"%"+orderReturnNumber.trim()+"%"));
                }
                if(StringUtils.isNotBlank(originalOrderNumber)){
                    //增加查询条件，原订单号
                    List<OrderReturn> orderReturns = findByOrderNum(originalOrderNumber);
                    //定义一个新的Predicate集合用于存放or条件
                    List<Predicate> predicateList = new ArrayList<>();
                    //增加查询条件：商品id
                    Join<OrderReturnItem,OrderReturn> join = root.join("orderReturn", JoinType.INNER);
                    Path<Long> queryOrderReturnId = join.get("Id");
                    orderReturns.forEach(orderReturn -> {
                        predicateList.add(cb.equal(queryOrderReturnId,orderReturn.getId()));
                    });
                    Predicate[] p1 = new Predicate[predicateList.size()];
                    //存放or条件
                    predicates.add(cb.or(predicateList.toArray(p1)));
                }
                if(!StringUtils.isBlank(orderReturnStatus)){
                    //增加查询条件：退单状态
                    Join<OrderReturnItem,OrderReturn> join = root.join("orderReturn", JoinType.INNER);
                    Path<String> queryStatus = join.get("status");
                    predicates.add(cb.equal(queryStatus,orderReturnStatus));
                }
                if(!StringUtils.isBlank(startTime)){
                    //增加查询条件：开始时间
                    Join<OrderReturnItem,OrderReturn> join = root.join("orderReturn", JoinType.INNER);
                    Path<Date> orderReturnQueryStartCreateTime = join.get("createdTimestamp");
                    Date startDate = DateUtils.parse(startTime, DateUtils.DEFAULT_DATE_FORMAT);
                    predicates.add(cb.greaterThanOrEqualTo(orderReturnQueryStartCreateTime,startDate));
                }
                if(!StringUtils.isBlank(endTime)){
                    //增加查询条件：结束时间
                    Join<OrderReturnItem,OrderReturn> join = root.join("orderReturn", JoinType.INNER);
                    Path<Date> orderReturnQueryEndCreateTime = join.get("createdTimestamp");
                    Date endData = DateUtils.parse(endTime, DateUtils.DEFAULT_DATE_FORMAT);
                    predicates.add(cb.lessThanOrEqualTo(orderReturnQueryEndCreateTime,endData));
                }
                if(CollectionUtils.isNotEmpty(merchantStoreIdList)){
                    Join<OrderReturnItem,OrderReturn> join = root.join("orderReturn", JoinType.INNER);
                    Path<Long> merchantStoreId = join.get("merchantStore").get("merchantId");
                    if(merchantStoreIdList.size() == 1){
                        predicates.add(cb.equal(merchantStoreId, merchantStoreIdList.get(0)));
                    }else{
                        CriteriaBuilder.In<Long> in = cb.in(merchantStoreId);
                        for(Long merchantId : merchantStoreIdList){
                            in.value(merchantId);
                        }
                        predicates.add(in);
                    }
                }
                if(!StringUtils.isBlank(productCode)){
                    //增加查询条件：商品sap编码
                    predicates.add(cb.like(root.get("externalId"),"%"+productCode.trim()+"%"));
                }
                if(!StringUtils.isBlank(productName)){
                    //增加查询条件，商品名
                    predicates.add(cb.like(root.get("skuName"),"%"+productName.trim()+"%"));
                }
                Predicate[] p = new Predicate[predicates.size()];
                return cb.and(predicates.toArray(p));
            }
        };
        Page<OrderReturnItem> orderReturnItemPage = orderReturnItemRepository.findAll(specification, pageable);
        Long totalElement = orderReturnItemPage.getTotalElements();
        List<OrderReturnItemVO> orderReturnItemVOList = new ArrayList<>();
        orderReturnItemPage.forEach(orderReturnItem -> {
            OrderReturnItemVO orderReturnItemVO = new OrderReturnItemVO();
            BeanUtils.copyProperties(orderReturnItem,orderReturnItemVO);
            //获取退单项的商品SKU
            ProductSku productSku = productSkuRepository.findOne(orderReturnItem.getSkuId());
            if(productSku != null){
                //设置退单项的SkuCode
                orderReturnItemVO.setSkuCode(productSku.getSkuCode());
                //设置退单项的skuExternalId
                orderReturnItemVO.setSkuExternalId(productSku.getExternalId());
                //设置退单项的totalPrice
                orderReturnItemVO.setTotalPrice(orderReturnItem.getSkuPrice().multiply(new BigDecimal(orderReturnItem.getSkuQuantity())));
                //获取品类名称,品牌名称
                Category category = productSku.getCategory();
                if(category != null){
                    orderReturnItemVO.setCategoryName(category.getCategoryName());
                }
                ProductBrand productBrand = productBrandRepository.findOne(productSku.getProductBrandId());
                if(productBrand != null){
                    orderReturnItemVO.setBrandName(productBrand.getBrandName());
                }
            }
            //获取orderReturn
            OrderReturn orderReturn = orderReturnItem.getOrderReturn();
            if(orderReturn!= null){
                OrderReturnVO orderReturnVO = new OrderReturnVO();
                BeanUtils.copyProperties(orderReturn,orderReturnVO);
                //设置退单的merchantStoreMessage
                MerchantStore merchantStore = orderReturn.getMerchantStore();
                if(merchantStore != null){
                    orderReturnVO.setMerchantStoreMessage("["+merchantStore.getExternalId()+"]"+merchantStore.getStoreName());
                }
                //设置退单的originalOrderNumber
                orderReturnVO.setOriginalOrderNumber(orderReturn.getRelatedOrder().getOrderNumber());
                //设置退单的创建时间
                orderReturnVO.setCreatedTimestamp(DateUtils.formatDate(orderReturn.getCreatedTimestamp(), DateUtils.DEFAULT_DATE_FORMAT));
                //设置原始订单类型
                orderReturnVO.setOrderType(orderReturn.getRelatedOrder().getOrderType());
                //设置退单项的所属订单
                orderReturnItemVO.setOrderReturnVO(orderReturnVO);
            }
            orderReturnItemVOList.add(orderReturnItemVO);
        });
        PageVO pageVO = new PageVO(pageCode,pageSize,totalElement.intValue(),orderReturnItemVOList);
        return pageVO;
    }

    /**
     * 根据原订单号查询退单
     * @param orderNum
     * @return
     */
    @Override
    public List<OrderReturn> findByOrderNum(String orderNum) {
        Specification<OrderReturn> specification = new Specification<OrderReturn>(){
            @Override
            public Predicate toPredicate(Root<OrderReturn> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();
                Join<OrderReturn, Order> join = root.join("relatedOrder");
                Path<String> queryOrderNum = join.get("orderNumber");
                predicates.add(cb.like(queryOrderNum,"%"+orderNum.trim()+"%"));
                Predicate[] p = new Predicate[predicates.size()];
                return cb.and(predicates.toArray(p));
            }
        };
        List<OrderReturn> orderReturns = orderReturnRepository.findAll(specification);
        return orderReturns;
    }

    /**
     * 根据门店名称查询退单
     * @param merchantName
     * @return
     */
    @Override
    public List<OrderReturn> findByMerchantName(String merchantName) {
        Specification<OrderReturn> specification = new Specification<OrderReturn>(){
            @Override
            public Predicate toPredicate(Root<OrderReturn> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();
                Join<OrderReturn, MerchantStore> join = root.join("merchantStore");
                Path<String> storeName = join.get("storeName");
                predicates.add(cb.like(storeName,"%"+merchantName.trim()+"%"));
                Predicate[] p = new Predicate[predicates.size()];
                return cb.and(predicates.toArray(p));
            }
        };
        List<OrderReturn> orderReturns = orderReturnRepository.findAll(specification);
        return orderReturns;
    }

    /**
     * 根据退单号查询退单
     * @param returnNumber
     * @return
     */
    public OrderReturn findByReturnNumber(String returnNumber) {
        return orderReturnRepository.findByReturnNumber(returnNumber);
    }

    @Override
    public OrderReturn findByReturnById(Long Id) {
        return orderReturnRepository.findOne(Id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void audit(User user, ReturnAuditModel auditModel) {
        OrderReturn orderReturn = orderReturnRepository.findOne(auditModel.getOrderReturnId());
        Order order = orderReturn.getRelatedOrder();
        if(CollectionUtils.isEmpty(orderReturn.getOrderReturnItems())){
            throw new OrderReturnAuditException("订单项为空，审核失败");
        }
        //退货且为现金购买优惠券订单
        if(ReturnType.RETURN.equalsIgnoreCase(orderReturn.getReturnType())
                &&OrderType.CASH_BY_COUPON.equalsIgnoreCase(order.getOrderType())){
            //更新信息
            orderReturn.setUpdatedBy(user.getAdminName());
            orderReturn.setUpdatedTimestamp(new Date());
            orderReturn.setStatus(OrderReturnStatus.CONFIRMED);
            orderReturnRepository.save(orderReturn);
        }else{
            throw new OrderReturnAuditException("暂不能审核此类退单");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refund(User user, Long orderReturnId) {
        OrderReturn orderReturn = orderReturnRepository.findOne(orderReturnId);
        Order order = orderReturn.getRelatedOrder();
        if(CollectionUtils.isEmpty(orderReturn.getOrderReturnItems())){
            throw new OrderReturnAuditException("订单项为空，创建退款申请失败");
        }
        //退货且为现金购买优惠券订单
        if(ReturnType.RETURN.equalsIgnoreCase(orderReturn.getReturnType())
                && OrderType.CASH_BY_COUPON.equalsIgnoreCase(order.getOrderType())) {
            //更新信息
            orderReturn.setUpdatedBy(user.getAdminName());
            orderReturn.setUpdatedTimestamp(new Date());
            List<OrderReturnItem> orderReturnItemList = orderReturn.getOrderReturnItems();
            orderReturnItemList.forEach(orderReturnItem -> {
                CouponDetail couponDetail = couponDetailRepository.findByCouponCode(orderReturnItem.getCouponCode());
                if (couponDetail == null || couponDetail.getIsUsed()) {
                    throw new OrderReturnAuditException("优惠券不存在或已使用，不能退还");
                }
                //将优惠券明细置为未购买
                couponDetail.setGeneratedTime(new Date());
                couponDetail.setCustomer(null);
                //保存优惠券退券记录
                Long transactionId = defaultUidGenerator.getUID();
                CouponHistroy histroy = new CouponHistroy(transactionId,
                        couponDetail.getCouponDetailId(),
                        orderReturn.getCustomer().getCustomerId(),
                        orderReturn.getReturnNumber(),
                        CouponHistroy.Operation.RETURN,
                        String.format("优惠券：券码%s 退款,退单：%s",couponDetail.getCouponCode(),orderReturn.getReturnNumber()));
                couponHistroyRepository.save(histroy);
                /*//积分兑换优惠券订单
                if (OrderType.BONUS_POINTS_BY_COUPON.equalsIgnoreCase(order.getOrderType())) {
                    BigInteger incrementValue = orderReturn.getRefundTotal().toBigInteger();
                    String remark = String.format("退还优惠券:%s，返还积分:%s", couponDetail.getCouponCode(), incrementValue);
                    bonusPointsService.incrementBonusPoints(
                            orderReturn.getCustomer(), order.getOrderNumber(), incrementValue, BonusPointsSource.MALL, BonusPointsUpdatedDetail.ORDER_REFUND, remark);
                    orderReturn.setStatus(OrderReturnStatus.FINISHED);
                }*/
                couponDetailRepository.save(couponDetail);
            });
            //增加优惠券可用数量
            try{
                couponRepository.incrementCouponQuantityAvailable(order.getCouponId(),1);
            }catch (Exception e){
                throw new RuntimeException("系统繁忙，请稍后重试。");
            }
            //现金购买优惠券订单创建退款请求
            if (OrderType.CASH_BY_COUPON.equalsIgnoreCase(order.getOrderType())) {
                if (refundRequestService.buildRefundRequest(orderReturn)) {
                    //修改退款状态为正在退款
                    orderReturn.setRefundStatus(RefundStatus.REFUNDDING);
                    //修改订单状态为已完成
                    orderReturn.setStatus(OrderReturnStatus.FINISHED);
                }
            }
            orderReturnRepository.save(orderReturn);
        }
    }

}
